<template>
  <div class="_fd-struct">
    <el-badge type="warning" is-dot :hidden="!configured">
      <el-button size="small" type="primary" plain @click="visible = true">{{ title || t('struct.title') }}</el-button>
    </el-badge>
    <el-dialog
      v-model="visible"
      class="_fd-struct-con"
      :title="title || t('struct.title')"
      destroy-on-close
      :close-on-click-modal="false"
      append-to-body
      width="800px"
    >
      <div v-if="visible" ref="editor"></div>
      <template #footer>
        <div>
          <el-button size="default" @click="visible = false">{{ t('props.cancel') }}</el-button>
          <el-button type="primary" size="default" color="#2f73ff" @click="onOk">{{ t('props.ok') }}</el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>

<script>
import 'codemirror/lib/codemirror.css'
import CodeMirror from 'codemirror/lib/codemirror'
import 'codemirror/mode/javascript/javascript'
import { deepParseFn, toJSON } from '../utils/index'
import { deepCopy } from '@form-create/utils/lib/deepextend'
import { defineComponent, markRaw } from 'vue'
import is from '@form-create/utils/lib/type'
import errorMessage from '../utils/message'

export default defineComponent({
  name: 'Struct',
  inject: ['designer'],
  props: {
    modelValue: [Object, Array, Function],
    title: String,
    defaultValue: {
      require: false
    },
    validate: Function
  },
  emits: ['update:modelValue'],
  data() {
    return {
      editor: null,
      visible: false,
      oldVal: null
    }
  },
  computed: {
    t() {
      return this.designer.setupState.t
    },
    configured() {
      return !is.empty(this.modelValue)
    }
  },
  watch: {
    modelValue() {
      this.load()
    },
    visible(n) {
      if (n) {
        this.load()
      }
    }
  },
  methods: {
    load() {
      const val = toJSON(deepParseFn(this.modelValue ? deepCopy(this.modelValue) : this.defaultValue))
      this.oldVal = val
      this.$nextTick(() => {
        this.editor = markRaw(
          CodeMirror(this.$refs.editor, {
            lineNumbers: true,
            mode: 'javascript',
            lint: true,
            line: true,
            tabSize: 2,
            lineWrapping: true,
            value: val || ''
          })
        )
      })
    },
    onOk() {
      const str = this.editor.getValue()
      let val
      try {
        val = new Function('return ' + str)()
      } catch (e) {
        console.error(e)
        errorMessage(this.t('struct.errorMsg'))
        return false
      }
      if (this.validate && this.validate(val) === false) {
        errorMessage(this.t('struct.errorMsg'))
        return false
      }
      this.visible = false
      if (toJSON(val, null, 2) !== this.oldVal) {
        this.$emit('update:modelValue', val)
      }
      return true
    }
  }
})
</script>

<style>
._fd-struct {
  width: 100%;
}

._fd-struct .el-badge {
  width: 100%;
}

._fd-struct .el-button {
  font-weight: 400;
  width: 100%;
}

._fd-struct-con .CodeMirror {
  height: 500px;
}

._fd-struct-con .el-dialog__body {
  padding: 0px;
}
</style>
